# -*- coding: utf-8 -*-
import time
from datetime import date, datetime, timedelta

from event import event_type
from settings import CLIENT_TZ, SECRET_KEY
import pytz
import string
import random
import hashlib
import logging
from utility.error_code import error_code
from utility.message_manager import MessageBusManager
from utility.odoo_manager import OdooManager

DATE_FORMAT = "%Y-%m-%d"
TIME_FORMAT = "%H:%M:%S"
DATETIME_FORMAT = "%s %s" % (DATE_FORMAT, TIME_FORMAT)
DATE_LENGTH = len(date.today().strftime(DATE_FORMAT))
DATETIME_LENGTH = len(datetime.now().strftime(DATETIME_FORMAT))
#  检查类型
CHECKTYPE={
    '1': '孕期初检',
    '2': '常规检查',
    '3': '产后42天检查'
}
_logger = logging.getLogger(__name__)


def context_today(timestamp=None):
    """ Return the current date as seen in the client's timezone in a format
        fit for date fields. This method may be used to compute default
        values.

        :param datetime timestamp: optional datetime value to use instead of
            the current date and time (must be a datetime, regular dates
            can't be converted between timezones.)
        :rtype: str
    """
    today = timestamp or datetime.now()
    context_today = None
    tz_name = CLIENT_TZ
    if tz_name:
        try:
            today_utc = pytz.timezone('UTC').localize(today, is_dst=False)  # UTC = no DST
            context_today = today_utc.astimezone(pytz.timezone(tz_name))
        except Exception:
            _logger.debug("failed to compute context/client-specific today date, using UTC value for `today`",
                          exc_info=True)
    return (context_today or today).strftime(DATE_FORMAT)


def from_string(value):
    """ Convert an ORM ``value`` into a :class:`date` value. """
    if not value:
        return None
    value = value[:DATE_LENGTH]
    return datetime.strptime(value, DATE_FORMAT).date()


def to_string(value):
    """ Convert a :class:`date` value into the format expected by the ORM. """
    return value.strftime(DATE_FORMAT) if value else False


def get_context_year():
    """获取客户端时区的当前年"""
    return from_string(context_today()).strftime('%Y')


def get_context_month():
    """获取客户端时区的当前月份"""
    month = from_string(context_today()).strftime('%m')
    month = str(int(month))
    return month


def get_context_day():
    """获取客户端时区的当前日"""
    day = from_string(context_today()).strftime('%d')
    day = str(int(day))
    return day

def get_current_week ():
    now_week = from_string(context_today()).weekday()
    # 当前日期 - now_week天 为本周一的日期
    start_day = from_string(context_today(datetime.fromtimestamp(datetime.now().timestamp() - now_week * 24 * 60 * 60)))
    return str(from_string(context_today())), str(start_day)

def context_timestamp(timestamp=None):
    """Returns the given timestamp converted to the client's timezone.
       This method is *not* meant for use as a default initializer,
       because datetime fields are automatically converted upon
       display on client side. For default values :meth:`fields.datetime.now`
       should be used instead.

       :param datetime timestamp: naive datetime value (expressed in UTC)
                                  to be converted to the client timezone
       :rtype: datetime
       :return: timestamp converted to timezone-aware datetime in context
                timezone
    """
    timestamp = timestamp or datetime.now()
    tz_name = CLIENT_TZ
    utc_timestamp = pytz.utc.localize(timestamp, is_dst=False)  # UTC = no DST
    if tz_name:
        try:
            context_tz = pytz.timezone(tz_name)
            return (utc_timestamp.astimezone(context_tz) or timestamp).strftime(DATETIME_FORMAT)
        except Exception:
            _logger.debug("failed to compute context/client-specific timestamp, "
                          "using the UTC value",
                          exc_info=True)
    return utc_timestamp

def getSign(transactionId):
    md5 = hashlib.md5()
    md5.update((transactionId + SECRET_KEY).encode("utf8"))
    return md5.hexdigest()


def generate_nonce_str(length=32):
    return ''.join(random.SystemRandom().choice(
        string.ascii_letters + string.digits) for _ in range(length))

"""类转字典"""
def class_to_dict(obj):
    result = {}
    for name in dir(obj):
        value = getattr(obj, name)
        if not name.startswith('__') and not callable(value):
            result[name] = value
    return result

def get_params(request):
    params = {}
    headers = request.headers
    method = request.method
    if method == "GET":
        params = request.args
    elif method == "POST":
        content_type = headers.get('Content-Type')
        if "www-form" in content_type:  # 表单请求
            params = request.form
        elif "application/json" in content_type:  # json请求
            params = request.get_json()
    return params

#  必填参数校验
def  required_parame_verif(req_parames,params):
    '''
    params_ = params 
    if instance(params,list):
        params_ = {}
        for param in params:
            params_[param[1]]=param[-1]
    '''        
    for parame in  req_parames:
        try:
            if  parame not in  params.keys():
                return {'code': 300, 'msg': error_code[300].format(parame)}  
            if not  params.get(parame):
                return {'code': 413, 'msg': error_code[413].format(parame)}   
        except Exception as e:
            return {'code': 412, 'msg': error_code[412]}   
    return {'code': 0, 'msg': 'success', 'data': {}, 'success': True}  

def num_to_char(num):

    """数字转中文"""
    num_dict={"0":u"零","1":u"一","2":u"二","3":u"三","4":u"四","5":u"五","6":u"六","7":u"七","8":u"八","9":u"九"}
    num=str(num)
    new_str=""
    listnum=list(num)
    shu=[]
    for i in listnum:
        shu.append(num_dict[i])
    new_str="".join(shu)
    return new_str
    
#  计算年龄
def calculate_age(born):
    birthDate = datetime.strptime(born, "%d/%m/%Y").date()
    currentDate = datetime.today().date()
    age = currentDate.year - birthDate.year
    monthVeri = currentDate.month - birthDate.month
    dateVeri = currentDate.day - birthDate.day
    age = int(age)
    monthVeri = int(monthVeri)
    dateVeri = int(dateVeri)
    if monthVeri < 0 :
       age = age-1
    elif dateVeri < 0 and monthVeri == 0:
       age = age-1
    return  age  

# 根据身份证计算年龄
def calculate_age_by_card(card):
    birth_day = card[6:14]#出生年月日
    birth_year = birth_day[0:4]#前四位
    birth_month = birth_day[4:6]
    birth_date = birth_day[6:8]
    now = datetime.now()
    diff_year = now.year-int(birth_year)#int换算
    diff_month = now.month-int(birth_month)
    diff_day = now.day-int(birth_date)
    if diff_month<0 or diff_month==0 and diff_day<0:
        return diff_year -1
    return diff_year

# 解析省市code
# 原格式: [['北京市', 110000], ['北京市', 110000], ['北京市', 110000]]
def parse_area_code (province, city, country, town, village):
    data = {
        'province': province[0] if province else None,
        'city': city[0] if city else None,
        'country': country[0] if country else None,
        'town': town[0] if town else None,
        'village': village[0] if village else None,
        'code': []
    }
    if data['province']:
        data['code'].append(data['province'])
    if data['city']:
        data['code'].append(data['city'])
    else:
        return data
    if data['country']:
        data['code'].append(data['country'])
    else:
        return data
    if data['town']:
        data['code'].append(data['town'])
    else:
        return data
    if data['village']:
        data['code'].append(data['village'])
    else:
        return data
    return data

# 可选链获取字典值
def nullablea_dict (dict, key):
    try:
        return dict[key]
    except Exception as e:
        return  None

# 解析多对多时 list的构造
def parse_M2M_params (arr, type = 4):
    data = []
    if arr:
        for item in arr:
            if type == 4:
                i = (4, item)
            data.append(i)
    return data

# 检查当前档案的在途情况
# 1. 当前checkType的非在途时，是否有其他在途检查
# 2. 当前checkType的在途时，
def is_checking (archivesId, checkType):
    odoo = OdooManager().get_instance()
    # 获取当前档案的在途情况
    logs = odoo.env['inspection.log'].search_read([
        ('archives_id', '=', int(archivesId)),
        ('state', '=', '0')
    ])
    if logs:
        log = logs.pop()
        if (log['type'] == checkType):
            return {
                "res": True,
                "msg": "可操作",
                "logId": log['id']
            }
        else:
            return {
                "res": False,
                "msg": "请先完成在途检查"
            }
    else:
        return {
            "res": True,
            "logId": None
        }
# check检查流程
# 1. 初检需要在常规之前 且仅能有一次
# 2. 常规需要在初检之后 且在产后前
# 3. 产后仅能有一次
def check_progress(archivesId, checkType):
    odoo = OdooManager().get_instance()
    checking_log = odoo.env['inspection.log'].search_count([('archives_id', '=', int(archivesId)), ('state', '=', '0'), ('type', '=', checkType)])
    if checking_log:
        return {
            'data': True,
            'msg': "当前为在途新增，无需控制"
        }
    logs = odoo.env['inspection.log'].search_read([('archives_id', '=', int(archivesId)), ('state', '!=', '2')])
    if logs:
        beforeCount = 0
        commonCount = 0
        afterCount = 0
        for log in logs:
            if log['type'] == '1':
                beforeCount += 1
            elif log['type'] == '2':
                commonCount += 1
            elif log['type'] == '3':
                afterCount += 1
        if checkType == '1':
            if (beforeCount != 0):
                return {
                    'msg': '孕期初检仅可进行一次',
                    'data': False
                }
            if (commonCount != 0 or afterCount != 0):
                return {
                    'msg': '已进行常规产检或产后42天检查，无法开始孕期初检',
                    'data': False
                }
            return {
                'msg': True,
                'data': True
            }
        if checkType == '2':
            if (beforeCount == 0):
                return {
                    'msg': '请先进行孕期初检',
                    'data': False
                }
            if (afterCount != 0):
                return {
                    'msg': '已进行产后42天检查，无法开始常规产检',
                    'data': False
                }
            return {
                'msg': True,
                'data': True
            }
        if checkType == '3':
            if afterCount != 0:
                return {
                    'msg': '已完成产后42天检查，请勿重复进行',
                    'data': False
                }
            if beforeCount == 0 or commonCount == 0:
                return {
                    'msg': '请先完成前置检查',
                    'data': False
                }
            return {
                'data': True,
                'msg': True
            }
        return {
            'data': False,
            'msg': '未知错误'
        }
    else:
        return {
            'data': True,
            'msg': '可操作'
        }

# check体格检查
# 一般用于修改体格检查后 检查是否有未归档体格检查 并归档至该档案下
def check_physical (archivesId, checkType):
    odoo = OdooManager().get_instance()
    # 查询是否有未归档的体格检查
    physical = odoo.env['inspection.physical'].search_read([('archives_id', '=', int(archivesId)), ('inspection_log_id', '=', None)])
    if physical:
        physical = physical.pop()
    else:
        return
    # 查询是否有在途检查
    log = odoo.env['inspection.log'].search_read([('archives_id', '=', int(archivesId)), ('type', '=', checkType), ('state', '=', '0')])
    if log:
        log = log.pop()
        odoo.env['inspection.log'].write(log['id'], {
            'tgjx_id': physical['id']
        })
        message_bus = MessageBusManager().get_message_bus()
        create_event = event_type.OperationLogEvent('修改log记录', 'logid:{}'.format(log['id']))
        message_bus.handle(create_event)  # 发布事件
        odoo.env['inspection.physical'].write(physical['id'], {
            'inspection_log_id': log['id']
        })
        create_event = event_type.OperationLogEvent('修改体格检查记录', 'archivesId:{}'.format(archivesId))
        message_bus.handle(create_event)  # 发布事件
    # 新增一条log记录
    else:
        logId = odoo.env['inspection.log'].create({
            'state': '0',
            'archives_id': archivesId,
            'tgjx_id': physical['id'],
            'type': checkType
        })
        message_bus = MessageBusManager().get_message_bus()
        create_event = event_type.OperationLogEvent('创建log记录', 'logid:{}'.format(logId))
        message_bus.handle(create_event)  # 发布事件
        odoo.env['inspection.physical'].write(physical['id'], {
            'inspection_log_id': logId
        })
        create_event = event_type.OperationLogEvent('修改体格检查记录', 'archivesId:{}'.format(archivesId))
        message_bus.handle(create_event)  # 发布事件

# 根据孕周-周、孕周-天计算天数
# type 为1时根据天数 计算出孕周字符串
# type 为0时根据孕周-周、孕周-天 计算出天数
# type 为2时根据 n+n的格式解析
# type 为3时根据n天 解析出周数、天数
def parase_yz (type, week, day = 0):
    if type == 1:
        day = int(week)
        if not day:
            return 0
        else:
            if (day < 7):
                return '0' + str(day)
            else:
                week = int(day / 7)
                day = day - 7 * week
                return str(week) + '+' + str(day)
    elif type == 0:
        return (week or 0) * 7 + (day or 0)
    elif type == 2:
        strarr = week.split('+')
        week = int(strarr[0])
        day = int(strarr[1])
        return week, day
    elif type == 3:
        day = int(week)
        if not day:
            return 0, 0
        else:
            if (day < 7):
                return 0, day
            else:
                week = int(day / 7)
                day = day - 7 * week
                return week, day


# 通过时间 计算差额时间戳（描述）
# start开始时间 end 截止时间
def diff_datetime_count (start, end):
    timearray_start = time.strptime(start, "%Y-%m-%d %H:%M:%S")
    timearray_end = time.strptime(end, "%Y-%m-%d %H:%M:%S")
    return int(time.mktime(timearray_end) - time.mktime(timearray_start))
# 通过日期 计算差额日期（描述）
# start开始日期 end 截止日期
def diff_date_count (start, end):
    timearray_start = time.strptime(start, "%Y-%m-%d")
    timearray_end = time.strptime(end, "%Y-%m-%d")
    return int(time.mktime(timearray_end) - time.mktime(timearray_start)) / 60 / 60 / 24
#  获取当前周
def get_current_week(date=None):
    if date:
        duty_date = datetime.strptime(str(date), '%Y-%m-%d')
        monday, sunday = duty_date, duty_date
    else:
        monday, sunday = datetime.today(), datetime.today()
    one_day = timedelta(days=1)
    while monday.weekday() != 0:
        monday -= one_day
    while sunday.weekday() != 6:
        sunday += one_day
 
    # return monday, sunday
    # 返回时间字符串
    return datetime.strftime(monday, "%Y-%m-%d"), datetime.strftime(sunday, "%Y-%m-%d")


# 更新档案表的字段
def update_archives(archivesId, dict):
    odoo = OdooManager().get_instance()
    odoo.env['res.archives'].write(archivesId, dict)
    # 记录操作日志
    create_event = event_type.OperationLogEvent('更新档案信息', 'archives_id:{}'.format(archivesId))
    message_bus = MessageBusManager().get_message_bus()
    message_bus.handle(create_event)  # 发布事件
    
def diff_datetime_yz(start, end,yz):
    """
    动态计算孕周
    """
    timearray_start = time.strptime(start, "%Y-%m-%d %H:%M:%S")
    timearray_end = time.strptime(end, "%Y-%m-%d %H:%M:%S")
    days=int(time.mktime(timearray_end) - time.mktime(timearray_start)) 
    if int(days/7)==days/7:
        yz +=int(days/7)
    else:
        yz +=int(days/7)+1    
    return yz   